#pragma once

#ifdef WIN32
#include <Windows.h>
#endif

#include <iostream>
#include <stdint.h>
#include <thread>

class WSpinMutex
{
public:
    WSpinMutex() {}
    ~WSpinMutex() {}

    void lock()
    {
        uint32_t i = 0;
        while (!atomicCompareExchange(&_opFlag, _unlock, _locked))
        {
            if (i % 50 == 0) {
                std::this_thread::sleep_for(std::chrono::milliseconds(1));
                i++;
            }

            if (i > 2000000)
            {
                std::cout << "enQueue wait for spin lock failed, may dead locked" << std::endl;
                assert(false);
            }
        }
    }

    void unlock()
    {
        if (_opFlag != _locked)
        {
            return;
        }

        atomicCompareExchange(&_opFlag, _locked, _unlock);
    }

    template <typename T>
    static bool atomicCompareExchange(T *data, T expectValue, T newValue)
    {
#ifdef WIN32

        return (InterlockedCompareExchange(&_opFlag, newValue, expectValue) == expectValue);

#else
        return __sync_bool_compare_and_swap(data, expectValue, newValue);
#endif
    }

private:
    uint8_t _opFlag;
    const uint8_t _locked = 1;
    const uint8_t _unlock = 0;
};
